package com.goalias.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.goalias.constant.RedisConstants;
import com.goalias.constant.SystemConstants;
import com.goalias.domain.dto.ArticleDTO;
import com.goalias.domain.dto.ArticleQueryDTO;
import com.goalias.domain.entity.Article;
import com.goalias.domain.entity.Category;
import com.goalias.domain.entity.Tag;
import com.goalias.domain.vo.*;
import com.goalias.exception.BizException;
import com.goalias.exception.ExceptionEnum;
import com.goalias.mapper.ArticleMapper;
import com.goalias.resp.PageResult;
import com.goalias.resp.Result;
import com.goalias.service.IArticleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.goalias.service.ICategoryService;
import com.goalias.service.ITagService;
import com.goalias.service.RedisService;
import com.goalias.utils.DateUtils;
import com.goalias.utils.IoUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 文章表 服务实现类
 * </p>
 *
 * @author goalias
 * @since 2024-12-12
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IArticleService {

    @Resource
    private ICategoryService categoryService;

    @Resource
    private ITagService tagService;

    @Resource
    private RedisService redisService;

    @Resource
    private IoUtil iOUtil;

    @Override
    public List<Article> listNormalArticle() {
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
        wrapper.eq(Article::getDelFlag, 0);
        return list(wrapper);
    }

    @Override
    public Long getNormalArticleCount() {
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
        wrapper.eq(Article::getDelFlag, 0);
        return count(wrapper);
    }

    @Override
    public Result getHotArticleList() {
        // 查询出非草稿、没有被删除的文章，并按照热度降序排序前 3 文章
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
        wrapper.orderByDesc(Article::getViewCount);
        wrapper.eq(Article::getDelFlag, 0);

        Page<Article> page = new Page<>(1, 3);
        this.page(page, wrapper);

        List<Article> records = page.getRecords();
        for (Article record : records) {
            record.setThumbnail(StringUtils.hasText(record.getThumbnail()) ?
                    iOUtil.getUrl(iOUtil.getBUCKET_NAME(),record.getThumbnail()) :
                    iOUtil.getUrl(iOUtil.getBUCKET_NAME(),iOUtil.DEFAULT_THUMBNAIL()));
        }
        List<HotArticleVo> hotArticleVos = BeanUtil.copyToList(records, HotArticleVo.class);

        LambdaQueryWrapper<Article> timeWrapper = new LambdaQueryWrapper<>();
        timeWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
        timeWrapper.orderByDesc(Article::getCreateTime);
        timeWrapper.eq(Article::getDelFlag, 0);

        Page<Article> timePage = new Page<>(1, 8);
        this.page(timePage, timeWrapper);
        List<Article> timeRecords = timePage.getRecords();
        for (Article timeRecord : timeRecords) {
            timeRecord.setThumbnail(StringUtils.hasText(timeRecord.getThumbnail()) ?
                    iOUtil.getUrl(iOUtil.getBUCKET_NAME(),timeRecord.getThumbnail()) :
                    iOUtil.getUrl(iOUtil.getBUCKET_NAME(),iOUtil.DEFAULT_THUMBNAIL()));
        }
        List<HotArticleVo> timeArticleVos = BeanUtil.copyToList(timeRecords, HotArticleVo.class);
        return Result.success(new JSONObject()
                .set("hotArticles", hotArticleVos)
                .set("timeArticles", timeArticleVos));
    }

    @Override
    public Result getArticleList(ArticleQueryDTO articleQueryDTO) {
        // 构造查询条件
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Article::getStatus, articleQueryDTO.getStatus());
        wrapper.orderByDesc(Article::getIsTop).orderByDesc(Article::getCreateTime);
        wrapper.eq(articleQueryDTO.getCategoryId() != null, Article::getCategoryId, articleQueryDTO.getCategoryId());
        wrapper.eq(Article::getDelFlag, 0);

        if (articleQueryDTO.getTagId() != null) {
            wrapper.eq(Article::getTagId, articleQueryDTO.getTagId());
        }

        if (articleQueryDTO.getDate() != null) {
            try {
                Map<String, Date> dateRange = DateUtils.getDateRange(articleQueryDTO.getDate());
                wrapper.between(Article::getCreateTime, dateRange.get("start"), dateRange.get("end"));
            } catch (ParseException e) {
                throw new BizException(ExceptionEnum.DATE_NOT_VALID);
            }
        }

        // 从数据库中分页查询
        Page<Article> page = new Page<>(articleQueryDTO.getPageNum(), articleQueryDTO.getPageSize());
        this.page(page, wrapper);
        List<Article> articles = page.getRecords();

        // 设置文章分类名
        for (Article article : articles) {
            String categoryName = categoryService.getById(article.getCategoryId()).getName();
            article.setCategoryName(categoryName);
            article.setThumbnail(StringUtils.hasText(article.getThumbnail()) ?
                    iOUtil.getUrl(iOUtil.getBUCKET_NAME(),article.getThumbnail()) :
                    iOUtil.getUrl(iOUtil.getBUCKET_NAME(),iOUtil.DEFAULT_THUMBNAIL()));
        }

        List<ArticleListVo> articleListVos = BeanUtil.copyToList(articles, ArticleListVo.class);
        return Result.success(new PageResult<>(articleListVos, (long) articles.size(), page.getTotal()));
    }

    @Override
    public Result getArticleDetail(Long id) {
        // 从数据库中查询文章
        Article article = getById(id);
        if (ObjectUtil.isNull(article)) {
            return Result.error(ExceptionEnum.RESOURCE_NOT_EXIST);
        }
        ArticleDetailsVo articleDetailsVO = BeanUtil.copyProperties(article, ArticleDetailsVo.class);

        // 设置分类名称
        Category category = categoryService.getById(article.getCategoryId());
        if (category != null) {
            articleDetailsVO.setCategoryName(category.getName());
        }

        // 设置标签
        Tag tag = tagService.getById(article.getTagId());
        articleDetailsVO.setTagName(tag == null ? "无标签" : tag.getName());
        articleDetailsVO.setThumbnail(StringUtils.hasText(articleDetailsVO.getThumbnail()) ?
                iOUtil.getUrl(iOUtil.getBUCKET_NAME(),articleDetailsVO.getThumbnail()) :
                iOUtil.getUrl(iOUtil.getBUCKET_NAME(),iOUtil.DEFAULT_THUMBNAIL()));
        return Result.success(articleDetailsVO);
    }

    @Override
    public Result getArticleCount() {
        Long article = getNormalArticleCount();
        long category = categoryService.count();
        long tag = tagService.count();
        return Result.success(new ArticleCountVo(article, category, tag));
    }

    @Override
    public List<Article> listViewCount() {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(Article::getId, Article::getViewCount);
        return list(queryWrapper);
    }

    @Override
    public Result updateViewCount(Long id) {
        // 不检查 id 是否存在，这样可以直接更新新发表文章的阅读量
        redisService.hIncr(RedisConstants.ARTICLE_VIEW_COUNT_KEY, id.toString(), 1L);
        return Result.success();
    }

    @Override
    public Result getPreviousNextArticle(Long id) {
        // 查询当前的文章
        Article article = getById(id);
        if (ObjectUtil.isNull(article)){
            return Result.error(ExceptionEnum.RESOURCE_NOT_EXIST);
        }
        PreviousNextArticleVo previousNextArticleVo = new PreviousNextArticleVo();

        // 查询上一篇文章
        LambdaQueryWrapper<Article> previousWrapper = new LambdaQueryWrapper<>();
        previousWrapper.lt(Article::getCreateTime, article.getCreateTime());
        previousWrapper.orderByAsc(Article::getCreateTime).last("limit 1");
        previousWrapper.eq(Article::getDelFlag, 0);
        Article previousArticle = getOne(previousWrapper);
        if (previousArticle != null) {
            previousArticle.setThumbnail(StringUtils.hasText(previousArticle.getThumbnail()) ?
                    iOUtil.getUrl(iOUtil.getBUCKET_NAME(),previousArticle.getThumbnail()) :
                    iOUtil.getUrl(iOUtil.getBUCKET_NAME(),iOUtil.DEFAULT_THUMBNAIL()));
            previousNextArticleVo.setPrevious(BeanUtil.copyProperties(previousArticle, HotArticleVo.class));
        }

        // 查询下一篇文章
        LambdaQueryWrapper<Article> nextWrapper = new LambdaQueryWrapper<>();
        nextWrapper.gt(Article::getCreateTime, article.getCreateTime());
        nextWrapper.orderByAsc(Article::getCreateTime).last("limit 1");
        nextWrapper.eq(Article::getDelFlag, 0);
        Article nextArticle = getOne(nextWrapper);
        if (nextArticle != null) {
            nextArticle.setThumbnail(StringUtils.hasText(nextArticle.getThumbnail()) ?
                    iOUtil.getUrl(iOUtil.getBUCKET_NAME(),nextArticle.getThumbnail()) :
                    iOUtil.getUrl(iOUtil.getBUCKET_NAME(),iOUtil.DEFAULT_THUMBNAIL()));
            previousNextArticleVo.setNext(BeanUtil.copyProperties(nextArticle, HotArticleVo.class));
        }

        return Result.success(previousNextArticleVo);
    }

    @Override
    public Result addArticle(ArticleDTO article) {
        Article newArticle = BeanUtil.copyProperties(article, Article.class);

        // 设置分类 id
        Category category = categoryService.getOrAddCategoryByName(article.getCategory());
        newArticle.setCategoryId(category.getId());

        // 设置文章状态
        String status = article.getIsDraft() ? SystemConstants.ARTICLE_STATUS_Draft : SystemConstants.ARTICLE_STATUS_NORMAL;
        newArticle.setStatus(status);
        String isTop = article.getIsTop() ? "1" : "0";// 0 否   1 是
        newArticle.setIsTop(isTop);
        // 设置标签
        String tagName = article.getTagName();
        Long id = tagService.getOrAddTagByName(category.getId(), tagName).getId();
        newArticle.setTagId(id);
        saveOrUpdate(newArticle);
        return Result.success(newArticle.getId());
    }

    @Override
    public Result editArticle(ArticleDTO article) {
        return addArticle(article);
    }
}
